Math.PIOVER2 = .5 * Math.PI;
Math.PIOVER4 = .5 * Math.PIOVER2;
Math.TWOPI   = 2 * Math.PI;

Math.acosh = function(value)
{
	return Math.log(value + Math.sqrt(value * value - 1));
}

Math.asinh = function(value)
{
	return Math.log(value + Math.sqrt(value * value + 1));
}

Math.atanh = function(value)
{
	return .5 * Math.log((value + 1) / (1 - value));
}

Math.barycentric = function(value1, value2, value3, amount1, amount2)
{
	return value1 + (value2 - value1) * amount1 + (value3 - value1) * amount2;
}

Math.catmullRom = function(value1, value2, value3, value4, amount)
{
	var amountSquared = amount * amount;
	var amountCubed   = amountSquared * amount;
	return .5 * (2 * value2 + (value3 - value1) * amount + (2 * value1 - 5 * value2 + 4 * value3 - value4) * amountSquared + (3 * value2 - value1 - 3 * value3 + value4) * amountCubed);
}

Math.clamp = function(value, min, max)
{
	if (value < min)
		return min;
	if (value > max)
		return max;
	return value;
}

Math.cosh = function(value)
{
	return .5 * (Math.exp(value) + Math.exp(-value));
}

Math.distance = function(value1, value2)
{
	return Math.abs(value1 - value2);
}

Math.expm1 = function(value)
{
	if (Math.abs(x) < 1e-5)
		return value + .5 * value * value;
	return Math.exp(value) - 1;
}

// Improve this with Stirling approximation
Math.factorial = function(value)
{
	if (value <= 1)
		return 1;
	return value * Math.factorial(value - 1);
}

// Improve this with Stirling approximation
Math.gamma = function(value)
{
	return Math.factorial(value - 1);
}

Math.hermite = function(value1, tangent1, value2, tangent2, amount)
{
	var amountSquared = amount * amount;
    var amountCubed   = amountSquared * amount;
	if (amount == 0)
		return value1;
	if (amount == 1)
		return value2;
	return (2 * value1 - 2 * value2 + tangent2 + tangent1) * amountCubed + (3 * value2 - 3 * value1 - 2 * tangent1 - tangent2) * amountSquared + tangent1 * amount + value1;
}

Math.hypot = function(x, y)
{
	return Math.sqrt(x * x + y * y);
}

Math.hypotSquared = function(x, y)
{
	return x * x + y * y;
}

Math.ieeeRemainder = function(x, y)
{
    var regularMod        = x % y;
    var alternativeResult = regularMod - Math.sign(x) * Math.abs(y);
    if (Math.abs(alternativeResult) == Math.abs(regularMod))
	{
        var divisionResult = x / y;
        var roundedResult  = Math.round(divisionResult);
		return Math.abs(roundedResult) > Math.abs(divisionResult) ? alternativeResult : regularMod;
    }
	return Math.abs(alternativeResult) < Math.abs(regularMod) ? alternativeResult : regularMod;
}

Math.isPowerOfTwo = function(value)
{
	return (value > 0) && ((value & (value - 1)) == 0);
}

Math.lerp = function(value1, value2, amount)
{
	return value1 + (value2 - value1) * amount;
}

Math.log10 = function(value)
{
	return Math.log(value) / Math.LN10;
}

Math.log1p = function(value)
{
	if (Math.abs(value) > 1e-4)
		return Math.log(value + 1);
	return (1 - .5 * value) * value;
}

Math.rand = function(min, max)
{
	return Math.floor(Math.random() * (max - min + 1)) + min;
}

Math.sign = function(value)
{
	if (value < 0)
		return -1;
	if (value > 0)
		return 1;
	return 0;
}

Math.sinh = function(value)
{
	return .5 * (Math.exp(value) - Math.exp(-value));
}

Math.smoothStep = function(value1, value2, amount)
{
	return Math.hermite(value1, 0, value2, 0, amount);
}

Math.tanh = function(value)
{
	value = Math.exp(2 * value);
	return (value - 1) / (value + 1);
}

Math.toDegrees = function(radians)
{
	return radians * 57.295779513082320876798154814105;
}

Math.toRadians = function(degrees)
{
	return degrees * .017453292519943295769236907684886;
}

Math.truncate = function(value)
{
	return value < 0 ? Math.ceil(value) : Math.floor(value);
}

Math.wrapAngle = function(angle)
{
	angle = Math.ieeeRemainder(angle, Math.TWOPI);
	if (angle <= -Math.PI)
		angle += Math.TWOPI;
	else if (angle > Math.PI)
		angle -= Math.TWOPI;
	return angle;
}